package com.sam.demo.rabbitmq.sender;

import java.util.Date;
import java.util.Random;
import java.util.UUID;

import javax.annotation.PostConstruct;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.sam.demo.rabbitmq.message.SendData;

/**
 * 通过Publisher Confirms and Returns机制，生产者可以判断消息是否发送到了exchange及queue，而通过消费者确认机制，Rabbitmq可以决定是否重发消息给消费者，以保证消息被处理。
 * 根据RabbitMq官网定义，rabbitmq代理(broker)对发布者(publishers)的确认被称作发布者确认(publisher confirms)，这种机制是Rabbitmq对标准Amqp协议的扩展。
 * 因此通过这种机制可以确认消息是否发送给了目标。
 * 使用这种机制需要将Template模版publisherConfirms 或publisherReturns 属性设置为true，此外ConnectionFactory要配置为CachingConnectionFactory。
 */

/**
 * 通过Publisher Confirms and Returns机制，生产者可以判断消息是否发送到了exchange及queue，而通过消费者确认机制，Rabbitmq可以决定是否重发消息给消费者，以保证消息被处理。
 * 根据RabbitMq官网定义，rabbitmq代理(broker)对发布者(publishers)的确认被称作发布者确认(publisher confirms)，这种机制是Rabbitmq对标准Amqp协议的扩展。
 * 因此通过这种机制可以确认消息是否发送给了目标。
 * 使用这种机制需要将Template模版publisherConfirms 或publisherReturns 属性设置为true，此外ConnectionFactory要配置为CachingConnectionFactory。
 */

@Component
public class Sender implements RabbitTemplate.ConfirmCallback, ReturnCallback {
	
	@Autowired
    private RabbitTemplate rabbitTemplate;
	
	@PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }

	/**
	 * 当消息可以发送到Exchange时ack为true
	 * 当消息无法发送到Exchange被触发，此时ack为False，这时cause包含发送失败的原因
	 * spring.rabbitmq.publisher-confirms=true
	 */
	@Override
	public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {  
            System.out.println("消息发送至Exchange成功:" + correlationData.getId() + ",异常：" + cause);  
        } else {  
            System.out.println("消息发送至Exchange失败:" + correlationData.getId() + ",异常：" + cause);  
        }  
		
	}
	/**
	 * ReturnCallBack使用时需要通过RabbitTemplate 的setMandatory方法设置变量mandatoryExpression的值，该值可以是一个表达式或一个Boolean值。
	 * 当为TRUE时，如果消息无法发送到指定的消息队列那么ReturnCallBack回调方法会被调用。
	 * spring.rabbitmq.publisher-returns=true
	 * spring.rabbitmq.template.mandatory=true
	 */
	@Override
	public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
		System.out.println("消息发送至Exchange成功，发送至Topic失败。" + routingKey + "," + exchange + "," + replyText + replyCode + " 发送失败");
		
	}

	

    public void send(SendData data, int i){
    	CorrelationData correlationId = new CorrelationData(data.getId() + "");
    	
    	
//    	System.out.println("开始向fanoutExchange发送消息 : " + msg.toLowerCase());
//    	SendData data = new SendData();
//    	data.setId(100);
//    	data.setContent(msg.toLowerCase());
//    	data.setTime(new Date());
//    	// 转换消息并发送
//    	rabbitTemplate.convertAndSend("fanoutExchange", null, data, correlationId);
//    	System.out.println("结束向fanoutExchange发送消息 : " + msg.toLowerCase());
//    	System.out.println("--------------------------");

    	
//    	SendData data = new SendData();
//    	data.setContent(msg);
//    	data.setId(i);
//    	data.setTime(new Date());
    	
    	
    	System.out.println("开始向topicExchange发送消息 : " + data.getId() + ",routingKey=key." + i);
    	// 转换消息并发送,并且获取消费者返回值
    	rabbitTemplate.convertAndSend("topicExchange", "key." + i, data, correlationId);
    	System.out.println("结束向topicExchange发送消息 : " + data.getId() + ",routingKey=key." + i);
    	System.out.println("------------------------------------------------");
    }
}
